﻿///////////////////////////////////////////////////////////////////////////////////////////////////
//------------------------------版权声明----------------------------
//
// 此文件为 SuperMap iObjects .NET 的示范代码
// 版权所有：北京超图软件股份有限公司
//------------------------------------------------------------------
//
//-----------------------SuperMap iObjects .NET 示范程序说明--------------------------
//
//1、范例简介：
//   示范如何使用构建三维网络数据集，通过设置源或汇创建网络数据集的流向。
//   以地下管线爆破为场景，展示如何进行三维上游最近设施查找和下游追踪的分析。
//2、示例数据：
//   安装目录\SampleData\OpenScene\OpenScene.smwu
//   安装目录\SampleData\OpenScene\Pipe3D.udb
//   安装目录\SampleData\OpenScene\Pipe3D.udd
//3、关键类型/成员: 
//   Environment.IsSceneAntialias 事件
//   Environment.SceneAntialiasValue 事件
//   SceneControl.MouseDown 事件
//   SceneControl.ObjectSelected 事件
//   NetworkBuilder3D.BuildNetwork 方法
//   NetworkBuilder3D.BuildFacilityNetworkDirections 方法
//   FacilityAnalystSetting3D.NetworkDataset 属性
//   FacilityAnalystSetting3D.NodeIDField 属性
//   FacilityAnalystSetting3D.EdgeIDField 属性
//   FacilityAnalystSetting3D.FNodeIDField 属性
//   FacilityAnalystSetting3D.TNodeIDField 属性  
//   FacilityAnalystSetting3D.WeightFieldInfos 属性 
//   WeightFieldInfos3D.Add 方法
//   WeightFieldInfo3D.FTWeightField 属性
//   WeightFieldInfo3D.Name 属性
//   WeightFieldInfo3D.TFWeightField 属性
//   FacilityAnalyst3D.Check 方法
//   FacilityAnalyst3D.FindCriticalFacilitiesUpFromEdge 方法
//   FacilityAnalyst3D.TraceDownFromEdge 方法  
//4、使用步骤：
//   (1)在左侧的“构建网络参数设置”面板中分别选择构建网络数据集的三维点、线数据集以及打断模式，输入打断容限；
//   (2)单击“构建网络”按钮，构建三维网络数据集，并添加到当前场景窗口中；
//   (3)由于三维网络数据中的三维线数据集本身存在流向，因此创建流向是可选操作；
//   (4)单击“爆管分析”面板中单击“选取管线”按钮，然后在当前三维场景窗口中选择爆破的管线，爆管分析结果实时显示；
//   (5)单击“结果”面板中的两个表格中的任意单元格，弹出应关闭阀门或受影响管段的气泡；
//   (6)单击“爆管分析”面板中单击“清除”按钮，清空分析结果。
//---------------------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////
//------------------------------Copyright Statement----------------------------
//
// SuperMap iObjects .NET Sample Code
// Copyright: SuperMap Software Co., Ltd. All Rights Reserved.
//------------------------------------------------------------------
//
//-----------------------Description--------------------------
//
//1. Introduction:
//   How to construct the 3D network dataset by setting source or sink to construct the flow direction of network dataset.
//   How to conduct the 3D upstream closest facility and downstream tracking analysis.
//2. Data:
//   SampleData\OpenScene\OpenScene.smwu
//   SampleData\OpenScene\Pipe3D.udb
//   SampleData\OpenScene\Pipe3D.udd
//3. Key classes and members
//   Environment.IsSceneAntialias 
//   Environment.SceneAntialiasValue 
//   SceneControl.MouseDown 
//   SceneControl.ObjectSelected 
//   NetworkBuilder3D.BuildNetwork 
//   NetworkBuilder3D.BuildFacilityNetworkDirections 
//   FacilityAnalystSetting3D.NetworkDataset 
//   FacilityAnalystSetting3D.NodeIDField 
//   FacilityAnalystSetting3D.EdgeIDField 
//   FacilityAnalystSetting3D.FNodeIDField 
//   FacilityAnalystSetting3D.TNodeIDField 
//   FacilityAnalystSetting3D.WeightFieldInfos 
//   WeightFieldInfos3D.Add 
//   WeightFieldInfo3D.FTWeightField 
//   WeightFieldInfo3D.Name 
//   WeightFieldInfo3D.TFWeightField 
//   FacilityAnalyst3D.Check 
//   FacilityAnalyst3D.FindCriticalFacilitiesUpFromEdge 
//   FacilityAnalyst3D.TraceDownFromEdge 
//4. Steps:
//   (1)On the left, select 3D point, line dataset, and splitting mode. to construct the network dataset. Input the splitting tolerance;
//   (2)Click the Construct Network button. And add it to the current scene.
//   (3)The function to create flow direction is an optional;
//   (4)Click the Selec pipeline button on the Pipe-broken analysis panel.Select the pipeline on the current scene, and the result will be displayed in real-time.
//   (5)Click the result to pop up the bubble for closing;
//   (6)Click the Clear button on the Pipe-broken analysis panel.
//---------------------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////////////////////////


using SuperMap.Data;
using SuperMap.Realspace;
using SuperMap.Realspace.NetworkAnalyst;
using SuperMap.UI;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using Ycjw.PipeLine.Map.Basic.SuperMap;

namespace Ycjw.PipeLine.Map.Tools.Conditions.BGAnalysts
{
    public class BGAnalystsRun: SceneOperInterface
    {
        public override void UnRegister()
        {
            this.Clear();
            base.UnRegister();
        }

        private DataTable m_DataTableErrorResult = new DataTable();

        private DataTable m_DataTableResult = new DataTable();
        private DataTable m_DataTableEdge = new DataTable();

        private Sunny.UI.UILabel m_TextBoxPipeLineID;

        private Datasource Datasource
        {
            get
            {
                if (m_DatasetLine3D == null) return null;
                else
                {
                    return m_DatasetLine3D.Datasource;
                }
            }
        }

        private DatasetVector m_DatasetPoint3D;

        public DatasetVector DatasetPoint3D
        {
            set { m_DatasetPoint3D = value; }
        }

        private DatasetVector m_DatasetLine3D;

        public DatasetVector DatasetLine3D
        {
            set { m_DatasetLine3D = value; }
        }

        private List<String> m_NamesPoint3D;

        public List<String> NamesOfPoint3D
        {
            get { return m_NamesPoint3D; }
            set { m_NamesPoint3D = value; }
        }

        private List<String> m_NamesLine3D;

        public List<String> NamesOfLine3D
        {
            get { return m_NamesLine3D; }
            set { m_NamesLine3D = value; }
        }

        private List<String> m_NetworkDatasets;

        public List<String> NetworkDatasets
        {
            get { return m_NetworkDatasets; }
            set
            {
                m_NetworkDatasets = value;
            }
        }

        private List<String> m_Point3DFields;

        public List<String> Point3DFields
        {
            get { return GetDatasetPoint3DFields(); }
            set { m_Point3DFields = value; }
        }

        private List<String> m_Line3DFields;

        public List<String> Line3DFields
        {
            get { return GetDatasetLine3DFields(); }
            set { m_Line3DFields = value; }
        }


        // 设施网络分析
        // Facility Network Analyst
        private DatasetVector m_PipeNet;

        private FacilityAnalystSetting3D m_FacilityAnalystSetting;

        public FacilityAnalystSetting3D FacilityAnalystSetting
        {
            get { return m_FacilityAnalystSetting; }
        }



        private Int32[] m_ResultFacilities;

        private Int32[] m_ResultEdges;

        private Int32[] m_FacilitiesID;

        private FacilityAnalyst3D m_facilityAnalyst;


        private GeoLine3D m_SelectedLine;

        public GeoLine3D SelectedLine
        {
            get { return this.m_SelectedLine; }
        }

        public DataTable DataTableResult { get => m_DataTableResult; }
        public DataTable DataTableErrorResult { get => m_DataTableErrorResult; }
        public DataTable DataTableEdge { get => m_DataTableEdge; }

        private Layer3DDataset m_LayerNetLine;

        private Layer3DDataset m_LayerNetNode;

        private InformationBubble m_InformationBubble;

        /// <summary>
        /// 根据sceneControl构造 SampleRun对象
        /// Construct the SampleRun according to the sceneControl
        /// </summary>
        public BGAnalystsRun(SceneControl sceneControl, Sunny.UI.UILabel textBoxPipeLineID,InformationBubble informationBubble, Form formMain) : base(sceneControl, formMain)
        {
            try
            {
                m_SceneControl = sceneControl;
                m_TextBoxPipeLineID = textBoxPipeLineID;
                m_InformationBubble = informationBubble;
                Initialize();
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
        }


        private void Initialize()
        {
            try
            {

                // 调整sceneControl的状态
                // Adjust the sceneControl
                m_SceneControl.Action = Action3D.Pan;
                m_SceneControl.Scene.Underground.IsVisible = true;
                m_SceneControl.Scene.GlobalImage.Transparency = 50;

                m_NamesPoint3D = new List<String>();

                m_NamesLine3D = new List<String>();

                m_NetworkDatasets = new List<String>();

                m_Point3DFields = new List<String>();

                m_Line3DFields = new List<String>();

                m_SourcePoints = new List<Int32>();

                m_SinkPoints = new List<Int32>();

                m_facilityAnalyst = new FacilityAnalyst3D();
                m_FacilityAnalystSetting = new FacilityAnalystSetting3D();

                m_SceneControl.BubbleInitialize += new BubbleInitializeEventHandler(SceneControl_BubbleInitialize);
                m_SceneControl.BubbleClose += new BubbleCloseEventHandler(SceneControl_BubbleClose);
                m_SceneControl.BubbleResize += new BubbleResizeEventHandler(SceneControl_BubbleResize);
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
        }

        void SceneControl_BubbleInitialize(object sender, BubbleEventArgs e)
        {
            System.Drawing.Point point = new Point(e.Bubble.ClientLeft, e.Bubble.ClientTop);
            m_InformationBubble.Location = point;
            m_InformationBubble.Visible = true;
        }

        void SceneControl_BubbleClose(object sender, BubbleEventArgs e)
        {
            m_InformationBubble.Visible = false;
        }

        void SceneControl_BubbleResize(object sender, BubbleEventArgs e)
        {
            System.Drawing.Point point = new Point(e.Bubble.ClientLeft, e.Bubble.ClientTop);
            m_InformationBubble.Location = point;
            m_InformationBubble.Visible = true;
        }
       
        /// <summary>
        /// 构建三维网络数据集
        /// Construct the 3D network dataset
        /// </summary>
        /// <param name="splitMode"></param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        public Boolean BuildNet(Int32 splitMode, double tolerance)
        {
            try
            {
                if (Datasource == null) return false;
                String networkName = Datasource.Datasets.GetAvailableDatasetName("PipeNet");

                if (m_DatasetLine3D == null)
                {
                    if (SuperMap.Data.Environment.CurrentCulture == "zh-CN")
                    {
                        Sunny.UI.UIMessageTip.ShowWarning("必须指定三维线数据集!");
                    }
                    else
                    {
                        Sunny.UI.UIMessageTip.ShowWarning("It is required to specify the 3D line dataset!");
                    }
                    return false;
                }
                else
                {

                    String[] lineFieldNames = GetDatasetLine3DFields().ToArray();

                    String[] pointFieldNames = GetDatasetPoint3DFields().ToArray();

                    //m_PipeNet = NetworkBuilder3D.BuildNetwork(m_DatasetLine3D, m_DatasetPoint3D, lineFieldNames, pointFieldNames, m_Datasource, networkName, mode, tolerance);
                    if (m_PipeNet != null)
                    {
                        m_FacilityAnalystSetting.NetworkDataset = m_PipeNet;

                        m_FacilityAnalystSetting.EdgeIDField = "SMEDGEID";
                        m_FacilityAnalystSetting.NodeIDField = "SMNODEID";
                        m_FacilityAnalystSetting.FNodeIDField = "SMFNODE";
                        m_FacilityAnalystSetting.TNodeIDField = "SMTNODE";

                        WeightFieldInfo3D weightFieldInfo = new WeightFieldInfo3D
                        {
                            Name = "Length",
                            FTWeightField = "SMLENGTH",
                            TFWeightField = "SMLENGTH"
                        };
                        WeightFieldInfos3D weightFieldInfos = new WeightFieldInfos3D
                        {
                            weightFieldInfo
                        };
                        m_FacilityAnalystSetting.WeightFieldInfos = weightFieldInfos;

                        if (SuperMap.Data.Environment.CurrentCulture == "zh-CN")
                        {
                            Sunny.UI.UIMessageTip.ShowOk("三维网络数据集构建成功！");
                        }
                        else
                        {
                            Sunny.UI.UIMessageTip.ShowOk("Construct the 3D network dataset successfully!");
                        }
                    }

                    // 检查网络数据集
                    // Check the network dataset
                    if (CheckNetworkDataset())
                    {
                        AddLayers(m_PipeNet);
                        return true;
                    }

                    else
                    {
                        return false;
                    }
                } 
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
                if (ex.Message == "“SuperMap.Realspace.NetworkAnalyst.NetworkBuilder3D”的类型初始值设定项引发异常。")
                {
                    if (SuperMap.Data.Environment.CurrentCulture == "zh-CN")
                    {
                        Sunny.UI.UIMessageTip.ShowWarning("请配置SuperMap Objects三维网络分析许可，否则无法进行三维网络分析。");
                    }
                    else
                    {
                        Sunny.UI.UIMessageTip.ShowWarning("Please configure the SuperMap Objects 3D network analysis license.");
                    }
                }
                return false;
            }
        }

        /// <summary>
        /// 以自定义专题的方式向场景中添加网络数据集
        /// </summary>
        /// <param name="networkDataset"></param>
        private void AddLayers(DatasetVector networkDataset)
        {
            Rectangle2D r2 = this.m_DatasetLine3D.Bounds;
            var points = new Point2Ds
            {
                new Point2D(r2.Left, r2.Top),
                new Point2D(r2.Right, r2.Top),
                new Point2D(r2.Right, r2.Bottom),
                new Point2D(r2.Left, r2.Bottom)
            };

            GeoRegion gr = new GeoRegion( points);
            m_SceneControl.Scene.GlobalImage.AddExcavationRegion(gr, "地表局部透明");

            foreach(Layer3D lyr in m_SceneControl.Scene.Layers)
            {
                if(lyr is Layer3DDataset)
                {
                    var l3ds = (lyr as Layer3DDataset);
                    var ds = l3ds.Dataset;
                    if (ds.Type == DatasetType.Network3D)
                    {
                        m_LayerNetLine = l3ds;
                    }
                }
            }
            if (m_LayerNetLine == null) return;
            var nodeLayerName = m_LayerNetLine.Name.Replace("@", "_Node@");
            var nodeLayerNameStart = nodeLayerName.Split('@')[0];
            foreach (Layer3D lyr in m_SceneControl.Scene.Layers)
            {
                if (lyr.Name.StartsWith(nodeLayerNameStart))
                {
                    m_LayerNetNode = lyr as Layer3DDataset;
                    break;
                }
            }
        }

        /// <summary>
        /// 检查所构建的网络数据集是否存在错误
        /// Whether there is an error in the created network dataset
        /// </summary>
        /// <returns></returns>
        private Boolean CheckNetworkDataset()
        {
            m_facilityAnalyst.AnalystSetting = m_FacilityAnalystSetting;
            FacilityAnalystCheckResult3D result = m_facilityAnalyst.Check();

            Dictionary<Int32, Int32> arcErrorInfos = result.ArcErrorInfos;
            Dictionary<Int32, Int32> nodeErrorInfos = result.NodeErrorInfos;

            if (arcErrorInfos.Count == 0 && nodeErrorInfos.Count == 0)
            {
                if (m_DataTableErrorResult != null)
                {
                    m_DataTableErrorResult.Rows.Clear();
                }
                return true;
            }
            else
            {
                Sunny.UI.UIMessageTip.ShowWarning("所构建的网络存在错误，无法进行分析！");

                DataColumn column1 = new DataColumn();
                DataColumn column2 = new DataColumn();
                DataColumn column3 = new DataColumn();

                column1.ColumnName = "编号";
                column2.ColumnName = "类型";
                column3.ColumnName = "错误类型";

                if (m_DataTableErrorResult != null)
                {
                    m_DataTableErrorResult.Columns.Add(column1);
                    m_DataTableErrorResult.Columns.Add(column2);
                    m_DataTableErrorResult.Columns.Add(column3);
                    FillDataGridTextBox(arcErrorInfos, nodeErrorInfos);
                }
                return false;
            }

        }


        private void FillDataGridTextBox(Dictionary<Int32, Int32> arcErrorInfos, Dictionary<Int32, Int32> nodeErrorInfos)
        {
            foreach (KeyValuePair<Int32, Int32> kv in nodeErrorInfos)
            {
                var dr = m_DataTableErrorResult.NewRow();
                Int32 nodeID = kv.Key;
                Int32 nodeErrorID = kv.Value;
                dr[0] = nodeID;
                dr[1] = "管点";
                dr[2] = GetErrorInfo(nodeErrorID);
                m_DataTableErrorResult.Rows.Add(dr);
            }
            foreach (KeyValuePair<Int32, Int32> kv in arcErrorInfos)
            {
                var dr = m_DataTableErrorResult.NewRow();
                Int32 arcID = kv.Key;
                Int32 arcErrorID = kv.Value;
                dr[0] = arcID;
                dr[1] = "管段";
                dr[2] = GetErrorInfo(arcErrorID);
                m_DataTableErrorResult.Rows.Add(dr);
            }

        }


        private String GetErrorInfo(Int32 type)
        {
            String error = String.Empty;
            switch (type)
            {
                case 1:
                    error = "结点ID重复";
                    break;
                case 2:
                    error = "弧段ID重复";
                    break;
                case 3:
                    error = "弧段没有对应结点";
                    break;
                case 4:
                    error = "空间位置不匹配";
                    break;
                case 5:
                    error = "复杂线对象";
                    break;
            }
            return error;
        }

        /// <summary>
        /// 构建网络数据集的流向
        /// Construct the flow direction of network dataset
        /// </summary>
        /// <param name="direction"></param>
        /// <param name="nodetype"></param>
        public void BuildDirections(String direction, String nodetype)
        {
            try
            {
                // 指定用来建立网络流向的源所对应的网络结点  
                // Specified the corresponding network node  
                m_FacilityAnalystSetting.DirectionField = direction;
                m_FacilityAnalystSetting.WeightFieldInfos[0].Name = "Length";

                Int32[] sourceIDs = null;
                Int32[] sinkIDs = null;

                if(m_SourcePoints.Count>0 || m_SinkPoints.Count>0)
                {
                    sourceIDs = m_SourcePoints.ToArray();
                    sinkIDs = m_SinkPoints.ToArray();
                    // 为三维网络数据集创建流向
                    // Create the flow direction for 3D network dataset
                    Boolean isSuccess = NetworkBuilder3D.BuildFacilityNetworkDirections(m_FacilityAnalystSetting, sourceIDs, sinkIDs, nodetype);

                    if (isSuccess)
                    {
                        if (SuperMap.Data.Environment.CurrentCulture == "zh-CN")
                        {
                             Sunny.UI.UIMessageTip.ShowWarning("流向创建成功！");
                        }
                        else
                        {
                             Sunny.UI.UIMessageTip.ShowWarning("Create the flow direction successfully!");
                        }
                    }
                    else
                    {
                        if (SuperMap.Data.Environment.CurrentCulture == "zh-CN")
                        {
                             Sunny.UI.UIMessageTip.ShowWarning("流向未创建成功！");
                        }
                        else
                        {
                             Sunny.UI.UIMessageTip.ShowWarning("Failed to create the flow direction!");
                        }
                    }
                }
                else{
                    if (SuperMap.Data.Environment.CurrentCulture == "zh-CN")
                    {
                         Sunny.UI.UIMessageTip.ShowWarning("未设置源或汇，无法创建网络流向");
                    }
                    else
                    {
                         Sunny.UI.UIMessageTip.ShowWarning("No source or sink. Can not create the network flow direction");
                    }
                    return;
                }

               

            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
        }
        
        /// <summary>
        /// 选择爆管管线
        /// Select the pipe
        /// </summary>
        public void SelectPipeLine()
        {
            if (m_LayerNetLine == null)
            {
                Sunny.UI.UIMessageTip.ShowWarning("没有选择管线！");
                return;
            }
            m_PointType = 2;
            m_LayerNetLine.IsSelectable = true;
            m_LayerNetNode.IsSelectable = false;
            m_SceneControl.Scene.TrackingLayer.Clear();
            m_LayerNetLine.Selection.Clear();
            m_LayerNetLine.Selection.Style.FillForeColor = Color.FromArgb(255, 179, 179, 255);
            m_LayerNetNode.Selection.Clear();
            m_TextBoxPipeLineID.Text = "";
            m_SceneControl.MouseDown -= new MouseEventHandler(SceneControl_MouseDown);
            m_SceneControl.MouseDown += new MouseEventHandler(SceneControl_MouseDown);
            m_SceneControl.ObjectSelected -= new ObjectSelectedEventHandler(SceneControl_ObjectSelected);
            m_SceneControl.ObjectSelected += new ObjectSelectedEventHandler(SceneControl_ObjectSelected);
            m_LayerNetLine.Selection.UpdateData();
        }


        /// <summary>
        /// 爆管分析
        /// Pipe-broken analysis
        /// </summary>
        public void PipeAnalyst()
        {
            m_LayerNetLine.IsSelectable = true;
            m_LayerNetNode.IsSelectable = true;
            m_facilityAnalyst.AnalystSetting = m_FacilityAnalystSetting;

            Boolean isLoad = m_facilityAnalyst.Load();

            Recordset recordset = null;
            try
            {
                recordset = m_PipeNet.ChildDataset.Query("SymbolID = 54435", CursorType.Static);

                Int32[] sourceNodeIDs = new Int32[recordset.RecordCount];

                recordset.MoveFirst();
                for (int i = 0; i < recordset.RecordCount; i++)
                {
                    sourceNodeIDs[i] = recordset.GetInt32("NodeID");
                    recordset.MoveNext();
                }

                // 上游最近设施点
                // Closest facility point in upstream
                FacilityAnalystResult3D resultFindCriticalFacilities = m_facilityAnalyst.FindCriticalFacilitiesUpFromEdge(sourceNodeIDs, m_SelectedLine.ID, true);
                m_ResultFacilities = resultFindCriticalFacilities.Nodes;
                // 下游追踪
                // Downstrem tracking
				FacilityAnalystResult3D resultTraceDown = m_facilityAnalyst.TraceDownFromEdge(m_SelectedLine.ID, "Length", true);
				m_ResultEdges = resultTraceDown.Edges;

                if (m_ResultFacilities.Length > 0 || m_ResultEdges.Length > 0)
                {
                    FillDataGridViewResult();

                    FillDataGridViewEdge();


                    GeoStyle3D style = new GeoStyle3D
                    {
                        FillForeColor = Color.FromArgb(100, 255, 255, 0)
                    };

                    m_LayerNetNode.Selection.AddRange(m_FacilitiesID);
                    m_LayerNetNode.Selection.Style = style;
                    m_LayerNetNode.Selection.UpdateData();

                    m_LayerNetLine.Selection.AddRange(m_ResultEdges);
                    style.LineColor = Color.FromArgb(100, 255, 0, 0);
                    m_LayerNetLine.Selection.Style = style;
                    m_LayerNetLine.Selection.UpdateData();
                }

            }
            catch (System.Exception e)
            {
                Trace.WriteLine(e.Message);
            }
            finally
            {
                if (recordset != null)
                {
                    recordset.Close();
                    recordset.Dispose();
                }
            }
        }

        private void FillDataGridViewResult()
        {
            DataColumn column1 = new DataColumn();
            DataColumn column2 = new DataColumn();
            DataColumn column3 = new DataColumn();
            DataColumn column4 = new DataColumn();
            column1.ColumnName = "应关闭阀门";
            column2.ColumnName = "埋深";
            column3.ColumnName = "经度";
            column4.ColumnName = "纬度";

            m_DataTableResult.Columns.Add(column1);
            m_DataTableResult.Columns.Add(column2);
            m_DataTableResult.Columns.Add(column3);
            m_DataTableResult.Columns.Add(column4);

            
            m_FacilitiesID = new Int32[m_ResultFacilities.Length];

            for (int i = 0; i < m_ResultFacilities.Length; i++)
            {
                var dr = m_DataTableResult.NewRow();
                string expression = "NodeID = " + m_ResultFacilities[i];
                Recordset node = m_PipeNet.ChildDataset.Query(expression, CursorType.Static);
                m_FacilitiesID[i] = node.GetInt32("SMID");
                dr[0] = m_FacilitiesID[i];
                dr[1] = (Double)node.GetFieldValue("BottomAltitude") + (Double)node.GetFieldValue("SMZ");
                dr[2] = String.Format("{0:F6}",node.GetFieldValue("SMX"));
                dr[3] = String.Format("{0:F6}",node.GetFieldValue("SMY"));

                m_DataTableResult.Rows.Add(dr);
            }
        }

        private void FillDataGridViewEdge()
        {
            DataColumn column1 = new DataColumn();
            DataColumn column2 = new DataColumn();
            DataColumn column3 = new DataColumn();
            DataColumn column4 = new DataColumn();

            column1.ColumnName = "受影响管段";
            column2.ColumnName = "长度";
            column3.ColumnName = "起始结点";
            column4.ColumnName = "终止结点";

            m_DataTableEdge.Columns.Add(column1);
            m_DataTableEdge.Columns.Add(column2);
            m_DataTableEdge.Columns.Add(column3);
            m_DataTableEdge.Columns.Add(column4);


            for (int i = 0; i < m_ResultEdges.Length; i++)
            {
                var dr = m_DataTableEdge.NewRow();

                String expression = "SMID = " + m_ResultEdges[i];
                Recordset edge = m_PipeNet.Query(expression, CursorType.Static);
                dr[0] = m_ResultEdges[i];
                dr[1] =  string.Format("{0:F6}",edge.GetFieldValue("SMLENGTH"));
                dr[2] = (int)edge.GetFieldValue("SMFNODE");
                dr[3] = (int)edge.GetFieldValue("SMTNODE");
                m_DataTableEdge.Rows.Add(dr);
            }
        }

        /// <summary>
        /// 根据在所点击的表格显示气泡
        /// Display the bubble
        /// </summary>
        /// <param name="geometry"></param>
        /// <param name="id"></param>
        private void DisplayBubble(Geometry3D geometry,Int32 id)
        {
            m_SceneControl.Bubbles.Clear();
            Bubble bubble = new Bubble();
            m_InformationBubble.Visible = true;

            if (geometry.Type == GeometryType.GeoPoint3D)
            {
                if (SuperMap.Data.Environment.CurrentCulture == "zh-CN")
                {
                    m_InformationBubble.Description.Text = "应关闭的阀门： ID = " + id;
                }
                else
                {
                    m_InformationBubble.Description.Text = "Closed pipe: ID = " + id; 
                }
            }

            else
            {
                if (SuperMap.Data.Environment.CurrentCulture == "zh-CN")
                {
                    m_InformationBubble.Description.Text = "受影响的管段：ID = " + id;
                }
                else
                {
                    m_InformationBubble.Description.Text = "Influenced pipe: ID = " + id; 
                }
            }
            bubble.Pointer = new Point3D(geometry.InnerPoint3D.X,geometry.InnerPoint3D.Y,-15);
            bubble.ClientWidth = m_InformationBubble.Width;
            bubble.ClientHeight = m_InformationBubble.Height;

            m_InformationBubble.Location = new Point(bubble.ClientLeft, bubble.ClientTop);
            m_SceneControl.Bubbles.Add(bubble);
            m_SceneControl.Scene.Refresh();
        }


        private string[] m_Point3DSysField = { "SMID", "SMX", "SMY", "SMZ", "SMUSERID", "SMGEOMETRYSIZE" };

        private String[] m_Line3DSysField = { "SMID", "SMLENGTH", "SMSDRIW", "SMSDRIN", "SMSDRIE", "SMSDRIS", "SMUSERID", "SMTOPOERROR", "SMGEOMETRYSIZE" };

        /// <summary>
        /// 判断给定的字段名称是否为系统字段
        /// Determine whether the given filed is the system field
        /// </summary>
        private Boolean IsSysField(String fieldName, DatasetType type)
        {
            bool result = false;

            try
            {
                if (type == DatasetType.Point3D)
                {
                    for (int i = 0; i < m_Point3DSysField.Length; i++)
                    {
                        if (m_Point3DSysField[i] == fieldName)
                        {
                            result = true;
                        }
                    }
                }
                else if (type == DatasetType.Line3D)
                {
                    for (int i = 0; i < m_Line3DSysField.Length; i++)
                    {
                        if (m_Line3DSysField[i] == fieldName)
                        {
                            result = true;
                        }
                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
                return result;
            }
        }

        

        private List<String> GetDatasetPoint3DFields()
        {
            m_Point3DFields.Clear();

            for (int i = 0; i < m_DatasetPoint3D.FieldCount; i++)
            {
                if (!IsSysField(m_DatasetPoint3D.FieldInfos[i].Name, DatasetType.Point3D))
                    m_Point3DFields.Add(m_DatasetPoint3D.FieldInfos[i].Name);
            }
            return m_Point3DFields;
        }

        private List<String> GetDatasetLine3DFields()
        {
            m_Line3DFields.Clear();

            for (int i = 0; i < m_DatasetLine3D.FieldCount; i++)
            {
                if (!IsSysField(m_DatasetLine3D.FieldInfos[i].Name, DatasetType.Line3D))
                    m_Line3DFields.Add(m_DatasetLine3D.FieldInfos[i].Name);
            }
            return m_Line3DFields;
        }

        public void SetNetPoint3D(DatasetVector dsv)
        {
            m_DatasetPoint3D = dsv;
        }

        public void SetNetLine3D(DatasetVector dsv)
        {
            m_DatasetLine3D = dsv;
            foreach (Dataset ds in Datasource.Datasets)
            {
                if (ds.Type == DatasetType.Network3D)
                {
                    m_PipeNet = ds as DatasetVector;
                    break;
                }
            }
        }

        private List<int> m_SourcePoints;

        private List<int> m_SinkPoints;

        private Point3D m_ClickPoint;

        private int m_PointType = 0;

        private Point m_MouseDownPoint;

        public void SetPoint(int pointType)
        {
            try
            {
                m_PointType = pointType;
                m_LayerNetNode.IsSelectable = true;
                m_LayerNetLine.IsSelectable = false;
                m_SceneControl.ObjectSelected -= new ObjectSelectedEventHandler(SceneControl_ObjectSelected);
                m_SceneControl.ObjectSelected += new ObjectSelectedEventHandler(SceneControl_ObjectSelected);
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// 在场景窗口按下鼠标事件
        /// The event for clicking on scene
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SceneControl_MouseDown(object sender, MouseEventArgs e)
        {
            try
            {
                if (e.Button == MouseButtons.Left && m_PointType == 2)
                {
                    m_MouseDownPoint = e.Location;
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// 在爆管点添加喷泉粒子，模拟水管爆破的效果
        /// Add the fountain particle in the pipe-broken
        /// </summary>
        /// <param name="pt3D"></param>
        private void AddFountainParticle(Point3D pt3D)
        {
            try
            {
                GeoPoint3D geopoint3d = new GeoPoint3D(pt3D);

                GeoParticle geoparticle = new GeoParticle(ParticleType.Fountain, geopoint3d);

                GeoStyle3D explodeStyle = new GeoStyle3D
                {
                    AltitudeMode = AltitudeMode.RelativeUnderGround
                };

                geoparticle.Style3D = explodeStyle;
                geoparticle.FromXML(@"..\..\SampleData\OpenScene\FountainParticle.par");

                m_SceneControl.Scene.TrackingLayer.Add(geoparticle, "ExplodeParticle");
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// 对象选择事件
        /// The event for selecting object
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SceneControl_ObjectSelected(object sender, ObjectSelectedEventArgs e)
        {
            Recordset recordset = null;
            try
            {
                // 无对象被选中
                // No selected object
                if (e.Count == 0)
                {
                    if (SuperMap.Data.Environment.CurrentCulture == "zh-CN")
                    {
                        Sunny.UI.UIMessageTip.ShowWarning("未选择对象!");

                    }
                    else
                    {
                        Sunny.UI.UIMessageTip.ShowWarning("No selected object!");
                    }
                }
                //有对象选中
                //Select ed object
                if (e.Count > 0)
                {
                    m_SceneControl.Action = Action3D.Pan2;

                    Selection3D[] selection3d = m_SceneControl.Scene.FindSelection(true);
                    recordset = selection3d[0].ToRecordset();

                    GeoStyle3D style = new GeoStyle3D
                    {
                        FillForeColor = Color.Red
                    };

                    // 源点
                    // Source point
                    if (m_PointType == 0)
                    {
                        m_LayerNetNode.Selection.Style = style;

                        GeoPoint3D sourcepoint = recordset.GetGeometry() as GeoPoint3D;
                        m_SourcePoints.Add(sourcepoint.ID);
                        if (m_SourcePoints.Count >1)
                        {
                            m_LayerNetNode.Selection.AddRange(m_SourcePoints.ToArray());
                        }
                        else{
                            m_LayerNetNode.Selection.Add(m_SourcePoints[0]);
                        }

                        m_LayerNetNode.Selection.UpdateData();
                    }

                    // 汇点
                    // Focal point
                    else if (m_PointType == 1)
                    {
                        style.FillForeColor = Color.Green;
                        m_LayerNetNode.Selection.Style = style;

                        GeoPoint3D sinkpoint = recordset.GetGeometry() as GeoPoint3D;
                        m_SinkPoints.Add(sinkpoint.ID);

                        if (m_SourcePoints.Count > 1)
                        {
                            m_LayerNetNode.Selection.AddRange(m_SinkPoints.ToArray());
                        }
                        else
                        {
                            m_LayerNetNode.Selection.Add(m_SinkPoints[0]);
                        }

                        m_LayerNetNode.Selection.UpdateData();

                    }
                    else
                    {
                        m_SelectedLine = recordset.GetGeometry() as GeoLine3D;
                        m_TextBoxPipeLineID.Text = m_SelectedLine.ID.ToString();

                        m_ClickPoint = new Point3D();
                        m_ClickPoint = m_SceneControl.Scene.PixelToGlobe(m_MouseDownPoint, PixelToGlobeMode.TerrainAndModel);

                        AddFountainParticle(m_ClickPoint);

                        PipeAnalyst();
                    }
                }
            }
            catch (System.Exception ex)
            {
                Trace.Write(ex.Message);
            }
            finally
            {
                if (recordset != null)
                {
                    recordset.Close();
                    recordset.Dispose();
                }
            }
        }


        /// <summary>
        /// 清除分析结果及表格
        /// Clear the analysis result and table
        /// </summary>
        public void Clear()
        {
            m_SceneControl.Bubbles.Clear();
            if(m_LayerNetLine != null) m_LayerNetLine.Selection.Clear();
            if (m_LayerNetNode != null) m_LayerNetNode.Selection.Clear();
            m_SceneControl.Scene.TrackingLayer.Clear();
            if (m_TextBoxPipeLineID != null) m_TextBoxPipeLineID.Text = "";
        }
    }
}


